'''
Created on Mar 23, 2011

@author: Christopher Nguyen
'''
import json

from django.http import HttpResponse
import gdata.books.service

import util


GBOOKS_MAX = 20 # Google limits max to 20
# input q or isbn, max/offset/indent
# output JSON from standards committee

API_RULESET = {
    'author': {
        'cond': lambda i: 'authors' in i,
        'cnvt': lambda i: i['authors']
    },
    'description': {
        'cond': lambda i: 'description' in i,
        'cnvt': lambda i: i['description']
    },
    'publisher': {
        'cond': lambda i: 'publishers' in i,
        'cnvt': lambda i: i['publishers']
    },
    'subject': {
        'cond': lambda i: 'subjects' in i,
        'cnvt': lambda i: i['subjects']
    },
    'title': {
        'cond': lambda i: 'title' in i,
        'cnvt': lambda i: i['title']
    },
    'isbn_10': {
        'cond': lambda i: len(extract_isbns(i['identifiers'], 10)) > 0,
        'cnvt': lambda i: extract_isbns(i['identifiers'], 10)[0]
    },
    'isbn_13': {
        'cond': lambda i: len(extract_isbns(i['identifiers'], 13)) > 0,
        'cnvt': lambda i: extract_isbns(i['identifiers'], 13)[0]
    }
}

def extract_isbns(identifiers, n):
    validator = getattr(util, 'valid_isbn_%d' % n)
    isbns = [y for (x,y) in identifiers
             if (x == 'ISBN') and
                len(y.replace('-', '')) == n and
                validator(y)]
    return isbns

def convert(entry):
    attr = util.convert(entry, API_RULESET)
    if len(attr) == 0:
        return None
    return {'type': 'book', 'attributes': attr}

def lookup(q, isbn=False, offset=1, max=0):
    if offset < 1: offset = 1
    if max <= 0: max = GBOOKS_MAX
    if isbn: q = 'isbn:%s' % isbn

    query = gdata.service.Query(text_query=q)
    service = gdata.books.service.BookService()
    data = service.search(q=query,
                          start_index=str(offset),
                          max_results=str(max))
    items = [convert(entry.to_dict()) for entry in data.entry]
    items = filter(lambda i: i is not None, items)
    return items

def search(request):
    # Extract optional arguments
    try:
        args = dict(request.GET.items())
        opts = {'indent': None, 'max': 0, 'offset': 0}
        for o in ['indent', 'max', 'offset']:
            if o in args:
                opts[o] = int(args[o])
                del args[o]
        
        q, isbn = '', False
        if 'isbn' in args: 
            isbn = util.isbn_10_13(args['isbn']) if len(args['isbn']) == 10 else args['isbn']
            if len(isbn) != 13: raise Exception('Invalid isbn \'%s\'' % isbn)
        else:
            q = ' '.join([args[arg] for arg in args if arg != 'isbn'])
        
        items = lookup(q, isbn, offset=opts['offset'], max=opts['max'])
        if opts['max'] == 0: opts['max'] = len(items)
        return HttpResponse(json.dumps(items[opts['offset']:(opts['max']+opts['offset'])], 
        indent = opts['indent']), mimetype = 'application/json')
    except:
        return util.error(0)
